mod json;
mod path;
mod query;
mod form;
#[cfg(feature = "auth")]
mod store;
#[cfg(feature = "header")]
mod header;

pub use json::Json;
pub use json::ValidJson;
pub use form::Form;
pub use form::ValidForm;
pub use path::Path;
pub use path::ValidPath;
pub use query::Query;
pub use query::ValidQuery;
#[cfg(feature = "auth")]
pub use store::UserStore;
#[cfg(feature = "header")]
pub use header::TypedHeader;

/// 为结构体实现[FromRequestParts]或[FromRequest]trait的宏
macro_rules! impl_from_request {
    ($name:ident, $wrapper:ident, FromRequestParts) => {
        impl<S, T> ::axum::extract::FromRequestParts<S> for $name<T>
        where
            T: ::serde::de::DeserializeOwned + ::validator::Validate,
            S: ::core::marker::Sync + ::core::marker::Send,
            $wrapper<T>: ::axum::extract::FromRequestParts<S, Rejection = $crate::ApiError>,
        {
            type Rejection = $crate::ApiError;

            async fn from_request_parts(
                parts: &mut axum::http::request::Parts,
                state: &S,
            ) -> Result<Self, Self::Rejection> {
                let $wrapper(v) = $wrapper::<T>::from_request_parts(parts, state).await?;
                v.validate()?;
                Ok($name(v))
            }
        }
    };
    ($name:ident, $wrapper:ident, FromRequest) => {
        impl<S, T> ::axum::extract::FromRequest<S> for $name<T>
        where
            T: ::serde::de::DeserializeOwned + ::validator::Validate,
            S: ::core::marker::Sync + ::core::marker::Send,
            $wrapper<T>: ::axum::extract::FromRequest<S, Rejection = $crate::ApiError>,
        {
            type Rejection = $crate::ApiError;

            async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
                let $wrapper(v) = $wrapper::<T>::from_request(req, state).await?;
                v.validate()?;
                Ok($name(v))
            }
        }
    };
}

impl_from_request!(ValidQuery, Query, FromRequestParts);
impl_from_request!(ValidPath, Path, FromRequestParts);
impl_from_request!(ValidJson, Json, FromRequest);
impl_from_request!(ValidForm, Form, FromRequest);